spring事务注解@Transactional 您所在的位置:网站首页 spring 事务注解 transactional spring事务注解@Transactional

spring事务注解@Transactional

2023-03-16 13:25| 来源: 网络整理| 查看: 265

1 概念

事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元。狭义上特指数据库事务,为保证事务正确、可靠,需要具备四个基本特性:原子性、一致性、隔离性、持久性。

spring为规范事务处理,提供了事务注解@Transactional,在编写事务性业务逻辑时,代码更简单、直观、清晰,本文主要对注解@Transactional使用中,遇到的常见问题、注意事项进行整理。

2 参数

@Transactional包含参数:

transactionManager 当系统中有多个事务管理器时,该属性可以指定匹配哪个事务管理器,如果只有一个事务管理器,系统会默认匹配。propagation 事务的传播规则,默认值为 REQUIRED。isolation 事务的隔离度,默认值为 DEFAULT,也就是跟当前所用的数据库的默认隔离级别一致。

timeout 超时时间, 单位秒,  是所注解方法的总耗时,如果超时,就会抛超时异常,并直接回滚该事务,默认值-1, 无限制。read-only 表明事务对DB的操作是否为只读,默认为false, 如果为true, 则只允许对数据库查询,不允许修改数据,否则抛异常。

rollbackFor 配置需回滚的受检异常类,  spring只对继承自RuntimeException、Error的异常进行回滚,受检异常不会回滚.noRollbackFor 配置不需要回滚的异常类。

3 隔离级别

枚举类Isolation(隔离级别),包含选项:

DEFAULT 默认,跟底层数据库的设置隔离级别一致,数据库设置的是什么就用什么。

READ_UNCOMMITTED 读未提交,该级别事务可以看到其他事务未提交的数据,存在脏读、幻读、不可重复读。READ_COMMITTED 读已提交,该级别的事务不会看到其他事务未提交的数据,存在幻读,不可重复读。REPEATABLE_READ 可重复读,该级别事务,可以保证读过的数据,即使其他事务已更新提交,也可以读到原来的值,仍存在幻读。(mysql数据库默认级别)SERIALIZABLE 串行化,隔离级别最高,性能最弱,不存在脏读、幻读、不可重复读问题。

4 传递规则

枚举类Propagation,包含选项:

名词描述是否事务数据库链接REQUIRED默认事务传递级别,配置该注解的方法,如果被包含在其他事务上下文中,则该方法逻辑会合并到当前事务,否则会新建事务(采用新的数据库链接)。是共享SUPPORTS配置该注解的方法,如果被包含在其他事务逻辑中,则该方法逻辑会合并到当前事务上下文中,否则不会新建事务,跟普通非事务方法一样。可能共享MANDATORY必须被包含在其他事务上下文中,自己不会新建发起事务,否则抛异常。是共享REQUIRES_NEW不管是否被包含在其他事务上下文中,自己都会新建独立的新事务(即采用新的数据库链接)。是独立NOT_SUPPORTED不管是否被包含在其他事务上下文中,都会采用自己独立的数据库链接,且以普通非事务方式处理。否独立NEVER必须以普通非事务方式处理,不允许被包含在其他事务逻辑中,否则抛异常。否独立NESTED

配置为该注解的方法,如果被包含在其他事务上下文中,则该方法的逻辑会作为"内嵌子事务"被包含在当前事务,它们共享一个数据库链接资源,否则会新建事务。

正常情况:跟REQUIRED一样,

回滚情况:注解NESTED事务的方法回滚, 不会影响包含它的上级事务, 上级事务仍然可以正常提交;而注解REQUIRED事务的方法回滚, 它的上级事务不能正确提交,也必须回滚。

是共享

补充说明:

事务传递性本质,就是一个事务遇上另个一个事务二者如何协调。 或者更准确的说,一个被标记@Transactional的方法被包含在事务上下文中,该方法如何跟包含它的事务上下文协调,是互相融洽、经济的共享当前数据库链接资源,还是自己仍然单干(独立申请数据库链接资源),二者只是相遇(视若无睹),还是势同水火。

不得不说,spring对事务传递性抽象很精炼,道出了事物与事物之间协作的本质,人与人之间的协作也一样,没什么不同。

5 回滚 5.1 @Transactional参数: rollbackFor,noRollbackFor

spring默认只对继承自RuntimeException、Error的异常进行回滚处理,对于继承自Exception的受检异常,事务不会自动回滚,如果需要回滚处理,需要对相关异常进行配置。 例如: @Transactional(rollbackFor={Exception.class})

5.2 事务间的影响

条件:只有在逻辑上,存在事务包含关系,且事务间共享一个数据库链接资源的情况,其中一个事务回滚,才有可能会导致整个事务上下文不能提交,只能回滚。

如果事务方法独占一个数据库链接资源,事务回滚就只跟它自己有关系,不会影响其他事务方法。

通过上面对事务传递规则梳理,其中REQUIRED、SUPPORTS、MANDATORY、NESTED这4中传递类型会跟上下文共享一个"数据库链接资源",也就是说这四种事务注解方法的事务回滚,会导致事务上下文不能提交,只能回滚,但其中NESTED是个例外,它是内嵌事务,可以只回滚自己,整个事务上下文仍可以正常提交。

提示:事务回滚是由该方法边界之外,spring事务拦截逻辑处理,方法内部只是屏蔽、吞掉异常,不会进行事务提交、回滚。

例: 假如在逻辑上,事务方法A包含事务方法B,且共享一个事务资源(NESTED除外),且A是整个事务的最外层边界。

场景一: A内有异常,B运行正常

方式1:如果该异常被A内部采用try逻辑给吞掉,整个事务仍会正常提交。 方式2:如果该异常没有被A吞掉,spring 会拦截该异常,依据上面说的异常回滚规则,进行提交或回滚。

场景二: A内正常,B内有异常

方式1:如果该异常被B内部采用try逻辑给吞掉,整个事务仍会正常提交。

方式2:如果该异常被A采用try逻辑给吞掉,实施上在B方法的逻辑边界,spring已拦截B的异常,并把事务标记为"回滚",此时整个事务已不能正常提交。 通常会出现如下异常: org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

情况三: A、B内都有异常

如果A的异常A自己内部吞掉,B的异常B自己内部吞掉,整个事务仍会正常提交,否则整个事务回滚。

理解: 尽管异常可以在事务方法内部给吞掉,这样事务就可以被正常提交,这并不代表符合业务逻辑规则,通常大多数情况是不符合业务规则的。

6 常见问题 6.1 异步处理

被标记@Transactional方法的内部,如果有异步处理逻辑,异步方法会申请独立的数据库链接资源,跟当前事务上下文,没有事务关系。

6.2 内部调用

Spring中,事务注解@Transactional是由AOP实现的,通过运行时动态生成代理对象,对目标对象进行增强,负责对事务进行开启、提交、回滚操作。 如果在一个类的内部,调用自己的方法,就算该方法被@Transactional注解,事务不会生效,需要通过它的代理类调用才可以,如下:

        MyService myService = (MyService)AopContext.currentProxy();         myService.doSomething();    

6.3 事务相互影响

两个@Transactional注解的事务方法,如果存在逻辑包含关系,是否互相影响,就看它们是共享一个DB事务,还是各自独立的DB事务,细节可以参考“5.2 事务间的影响”部分内容。

7 总结

在整个事务上下文运行期间,会独占珍贵的"数据库链接资源",内部逻辑应尽量简单、轻量,避免耗时逻辑。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有